package algorithm.queue;

import lombok.Data;

import java.util.Scanner;

/**
 * @ClassName : data_structure.queue.ArrayQueueDemo
 * @Description : 类描述
 * Created by cyd on 2021-01-19 21:55:36
 */
public class CircleQueueDemo {
    public static void main(String[] args) {
        CircleQueue queue = new CircleQueue(4);
        char key = ' ';
        Scanner scanner = new Scanner(System.in);
        boolean loop = true;

        while (loop) {
            System.out.println("----------------------");
            System.out.println("e：退出程序");
            System.out.println("s：显示队列");
            System.out.println("a：添加元素");
            System.out.println("g：取出元素");
            System.out.println("h：查看队列头");

            System.out.println("请输入指令：");
            key = scanner.next().charAt(0);
            switch (key) {
                case 's':
                    queue.showQueue();
                    break;
                case 'a':
                    System.out.println("----------------------");
                    System.out.println("请输入一个数：");
                    Integer value = scanner.nextInt();
                    try {
                        queue.addElement(value);

                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'g':
                    try {
                        Integer res = queue.getElement();
                        System.out.printf("取出来的数据是：%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'h':
                    try {
                        Integer res = queue.peek();
                        System.out.printf("取出来的数据是：%d\n", res);
                    } catch (Exception e) {
                        System.out.println(e.getMessage());
                    }
                    break;
                case 'e':
                    scanner.close();
                    loop = false;
                    break;
            }
        }
        System.out.println("程序已结束！");
    }
}

@Data
class CircleQueue {
    // 队列最大容量
    private Integer maxSize;
    // 头指针
    private Integer front;
    // 尾指针
    private Integer rear;
    // 队列容器
    private Integer[] arr;


    // 队列的构造器
    public CircleQueue(Integer arrMaxSize) {
        // rear指向的那一个元素，会被空出来，队列有效长度其实是arrMaxSize-1
        maxSize = arrMaxSize;
        arr = new Integer[maxSize];
        front = 0;
        rear = 0;
    }


    // 判断队列是否已满
    public boolean isFull() {
        return (rear + 1) % maxSize == front;
    }

    // 判断队列是否为空
    public boolean isEmpty() {
        return front.equals(rear);
    }

    // 队列添加元素
    public void addElement(Integer ele) {
        if (isFull()) {
            throw new RuntimeException("队列已满，添加失败");
        }
        // 因为rear指向队列最后一个元素之后一位
        arr[rear] = ele;
        // 将rear后移一位，这里考虑到循环，所以必须取模
        rear = (rear + 1) % maxSize;
    }

    // 队列剔除
    public Integer getElement() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空，取出失败");
        }
        // 因为front指向队列头
        Integer result = arr[front];
        // 将front后移一位，这里考虑到循环，所以必须取模
        front = (front + 1) % maxSize;
        return result;
    }

    // 读取当前队列的长度
    public Integer size() {
        return (rear + maxSize - front) % maxSize;
    }

    // 显示整个队列
    public void showQueue() {
        if (isEmpty()) {
            System.out.println("队列为空");
            return;
        }

        Integer size = size();
        for (int i = front; i < front + size; i++) {
            // i有可能超过数组长度的，比如maxSize=4，front=2，i可以取到5
            System.out.printf("arr[%d]=%d\n", i % maxSize, arr[i % maxSize]);
        }

    }

    // 查看队列头
    public Integer peek() {
        if (isEmpty()) {
            throw new RuntimeException("队列为空");
        }

        return arr[front];
    }
}
